console.log('你好ts')

function getData(){


}

var str:string="你好ts";

/*
1、使用编辑器vscode


2、typeScript中的数据类型

        布尔类型（boolean）
        数字类型（number）
        字符串类型(string)
        数组类型（array）
        元组类型（tuple）
        枚举类型（enum）
        
        任意类型（any）
        null 和 undefined
        void类型
        never类型

*/


//布尔类型（boolean）

    /*
    es5中 （正确写法）  ts中（错误写法）
        var flag=true;
        
        flag=456;
    */

 

    /*
     typescript中增加了类型校验

     写ts代码必须指定类型


    var flag:boolean=true;

    // flag=123;  //错误

    flag=false;  //正确

    console.log(flag);


    */



// 数字类型（number）


    /*
        var num:number=123;

        num=456;

        console.log(num);  /正确/


        num='str';    //错误
        
        */


// 字符串类型(string)


   /*
        var str:string='this is ts';

        str='haha';  //正确


        str=true;  //错误

   */
    


// 数组类型（array）  两种方式

    // 1.第一种

    
    
    var arr:number[]=[11,22,33];

    console.log(arr);


//2.第二种


  
    var arr2:Array<number>=[11,22,33];

    console.log(arr2)
    


//3、第三种

    var arr3:any[]=['131214',22,true];//any 多个不同的类型

    console.log(arr3);



// 元组类型（tuple）  属于数组的一种


// var arr:Array<number>=[11,22,33];

// console.log(arr)


//元祖类型
// let arr:[number,string]=[123,'this is ts'];

// console.log(arr);





/*



枚举类型（enum）

        enum 枚举名{ 
            标识符[=整型常数], 
            标识符[=整型常数], 
            ... 
            标识符[=整型常数], 
        } ;     

*/

        /*

            enum Flag {success=1,error=2};


            let s:Flag=Flag.success;

            console.log(s);



            enum Flag {success=1,error=2};


                let f:Flag=Flag.error;

                console.log(f);
        */



        /*
        000010

        -1

        -2


        */



    //    enum Color {blue,red,'orange'};


    //    var c:Color=Color.red;

    //    console.log(c);   //1  如果标识符没有赋值 它的值就是下标








    // enum Color {blue,red=3,'orange'};


    // // var c:Color=Color.red;

    // // console.log(c);   //3

    // var c:Color=Color.orange;
    // console.log(c);   //4


 //enum Err {'undefined'=-1,'null'=-2,'success'=1};


 //var e:Err=Err.success;

 //console.log(e);  打印1



// 任意类型（any）


// var num:any=123;

// num='str';

// num=true;

// console.log(num)



//任意类型的用处


var oBox:any=document.getElementById('box');


oBox.style.color='red';


// null 和 undefined  其他（never类型）数据类型的子类型



// var num:number;

// console.log(num)  //输出：undefined   报错




// var num:undefined;

// console.log(num)  //输出：undefined  //正确


// var num:number | undefined;


// num=123;

// console.log(num);


//定义没有赋值就是undefined
// var num:number | undefined;

// console.log(num);



// var num:null;


// num=null;


//一个元素可能是 number类型 可能是null 可能是undefined


var num:number | null | undefined;


num=1234;

console.log(num)





// void类型 :typescript中的void表示没有任何类型，一般用于定义方法的时候方法没有返回值。



//es5中的定义方法
// function run(){

//     console.log('run')
// }

// run();



//表示方法没有返回任何类型

/* 
//ts中的写法
function run():void{

        console.log('run')
    }

    run();
    
    */


// never类型:是其他类型 （包括 null 和 undefined）的子类型，代表从不会出现的值。

//这意味着声明never的变量只能被never类型所赋值。


/*

var a:undefined;

a=undefined;



var b:null;

b=null;


*/



var a:never;

//    a=123; //错误的写法
a=(()=>{

    throw new Error('错误');
})()

/*
3、typeScript中的函数

    3.1、函数的定义
    3.2、可选参数
    3.3、默认参数
    3.4、剩余参数
    3.5、函数重载
    3.6、箭头函数  es6


*/


// 3.1、函数的定义

//ts中定义函数的方法


 //函数声明法
        // function run():string{

        //     return 'run';
        // }


        //错误写法(类型错误)
        // function run():string{

        //     return 123;
        // }



//匿名函数


    // var fun2=function():number{

    //     return 123;
    // }


    // alert(fun2()); /*调用方法*/





//ts中定义方法传参



    /*
        function getInfo(name:string,age:number):string{

                return `${name} --- ${age}`;
        }


        alert(getInfo('zhangsan',20));

    */


    // var getInfo=function(name:string,age:number):string{

    //     return `${name} --- ${age}`;
    // }
       
    // alert(getInfo('zhangsan',40));




//没有返回值的方法

        // function run():void{

        //     console.log('run')
        // }
        // run();




// 3.2、方法可选参数 

        // es5里面方法的实参和行参可以不一样，但是ts中必须一样，如果不一样就需要配置可选参数 


       /*
        function getInfo(name:string,age?:number):string{

                if(age){

                    return `${name} --- ${age}`;
                }else{

                    return `${name} ---年龄保密`;
                }


        }

        alert(getInfo('zhangsan'))

        alert(getInfo('zhangsan',123))
       */



    //注意:可选参数必须配置到参数的最后面

    //错误写法
      /*
       function getInfo(name?:string,age:number):string{

                if(age){

                    return `${name} --- ${age}`;
                }else{

                    return `${name} ---年龄保密`;
                }
               

        }

        alert(getInfo('zhangsan'))
      */


// 3.3、默认参数 可选参数


        // es5里面没法设置默认参数，es6和ts中都可以设置默认参数

        /*

                function getInfo(name:string,age:number=20):string{

                            if(age){

                                return `${name} --- ${age}`;
                            }else{

                                return `${name} ---年龄保密`;
                            }
                        

                }

                // alert( getInfo('张三'));
                alert( getInfo('张三',30));
        */




// 3.4、剩余参数



            // function sum(a:number,b:number,c:number,d:number):number{

            //     return a+b+c+d;

            // }


            // alert(sum(1,2,3,4)) ;


    //三点运算符 接受新参传过来的值


        /*
            function sum(...result:number[]):number{

                
                var sum=0;

                for(var i=0;i<result.length;i++){

                    sum+=result[i];  
                }

                return sum;

            }

            alert(sum(1,2,3,4,5,6)) ;
        */




    /*

        function sum(a:number,b:number,...result:number[]):number{

                    
                var sum=a+b;

                for(var i=0;i<result.length;i++){

                    sum+=result[i];  
                }

                return sum;

            }

            alert(sum(1,2,3,4,5,6)) ;
    */
                    


// 3.5、ts函数重载

    // 重载：通过为同一个函数提供多个函数类型定义来试下多种功能的目的。


    //出现同名方法，下面的会替换上面的方法 
        /*
            function css(config){

            }

            function css(config,value){


            }
        */



    //ts 重载

                // function getInfo(name:string):string;

                // function getInfo(age:number):string;

                // function getInfo(str:any):any{

                //     if(typeof str==='string'){

                //         return '我叫：'+str;
                //     }else{

                //         return '我的年龄是'+str;
                //     }

                // }

                // alert(getInfo('张三'));   //正确


                // alert(getInfo(20));   //正确


                // alert(getInfo(true));    //错误写法

    

                function getInfo(name:string):string;
                function getInfo(name:string,age:number):string;
                function getInfo(name:any,age?:any):any{
                    if(age){

                        return '我叫：'+name+'我的年龄是'+age;
                    }else{

                        return '我叫：'+name;
                    }
                }

                // alert(getInfo('zhangsan'));  /*正确*/

                // alert(getInfo(123));  错误

                // alert(getInfo('zhangsan',20));




// 3.6、箭头函数


//this指向   箭头函数里面的this指向上下文


            

        // setTimeout(function(){

        //     alert('run')
        // },1000)



        setTimeout(()=>{

            alert('run')
        },1000)

    /*

        4、typeScript中的类

        4.1 类的定义
        4.2 继承
        4.3 类里面的修饰符
        4.4 静态属性 静态方法
        4.5 抽象类 继承 多态
    
        
    */
    
    
    //1、ts中类的定义
    
        /*
        es5:
    
            function Person(name){
    
                this.name=name;
    
                this.run=function(){
    
                    console.log(this.name)
                }
            }
    
            var p=new Person('张三');
    
            p.run()
        */
    
    
      /*
            ts中定义类：
    
    
                class Person{
    
                    name:string;   //属性  前面省略了public关键词
    
                    constructor(n:string){  //构造函数   实例化类的时候触发的方法
                        this.name=n;
                    }
    
                    run():void{
    
                        alert(this.name);
                    }
    
                }
                var p=new Person('张三');
    
                p.run()
      
      */
    
    
    
        /*
        class Person{
    
            name:string; 
    
            constructor(name:string){  //构造函数   实例化类的时候触发的方法
                this.name=name;
            }
    
            getName():string{
    
                return this.name;
            }
            setName(name:string):void{
    
                this.name=name;
            }
        }
        var p=new Person('张三');
    
        alert(p.getName());
    
    
        p.setName('李四');
    
    
        alert(p.getName());
    
    */
    
    
    
    
    
    //2、ts中实现继承  extends、 super
    
    
        // class Person{
    
        //     name:string;
    
        //     constructor(name:string){
        //         this.name=name;
        //     }
    
        //     run():string{
    
        //         return `${this.name}在运动`
        //     }
        // }
        // // var p=new Person('王五');
        // // alert(p.run())
    
    
        // class Web extends Person{
        //     constructor(name:string){
    
        //         super(name);  /*初始化父类的构造函数*/
        //     }
        // }
    
    
        // var w=new Web('李四');
        // alert(w.run());
    
    
    
    
    
    
        //ts  父类的方法和子类的方法一致
    
            // class Person{
    
            //     name:string;
    
            //     constructor(name:string){
            //         this.name=name;
            //     }
    
            //     run():string{
    
            //         return `${this.name}在运动`
            //     }
            // }
            // // var p=new Person('王五');
            // // alert(p.run())
    
    
            // class Web extends Person{
            //     constructor(name:string){
    
            //         super(name);  /*初始化父类的构造函数*/
            //     }
            //     run():string{
    
            //         return `${this.name}在运动-子类`
            //     }
            //     work(){
    
            //         alert(`${this.name}在工作`)
            //     }
            // }
    
    
            // var w=new Web('李四');
            // // alert(w.run());
    
            // // w.work();
    
            // alert(w.run());
    
    
    
    
    
    
    
    
    
    // 3 类里面的修饰符   三种修饰符
    
    /*
        public :公有          在当前类里面、 子类  、类外面都可以访问
        protected：保护类型    在当前类里面、子类里面可以访问 ，在类外部没法访问
        private ：私有         在当前类里面可以访问，子类、类外部都没法访问
    
        默认就是 public
    
    */
    
    
    
    //public :公有          在类里面、 子类  、类外面都可以访问
    
    
                //   class Person{
    
                //         public name:string;  /*公有属性*/
    
                //         constructor(name:string){
                //             this.name=name;
                //         }
    
                //         run():string{
    
                //             return `${this.name}在运动`
                //         }
                //     }
                //     // var p=new Person('王五');
                //     // alert(p.run())
    
    
                //     class Web extends Person{
                //         constructor(name:string){
    
                //             super(name);  
                //         }
                //         run():string{
    
                //             return `${this.name}在运动-子类`
                //         }
                //         work(){
    
                //             alert(`${this.name}在工作`)
                //         }
                //     }
    
                //     var w=new Web('李四');
    
                //     w.work();
    
    
            //类外部访问公有属性
    
    
                    //   class Person{
    
                    //     public name:string;  /*公有属性*/
    
                    //     constructor(name:string){
                    //         this.name=name;
                    //     }
    
                    //     run():string{
    
                    //         return `${this.name}在运动`
                    //     }
                    // }
    
                    // var  p=new Person('哈哈哈');
    
                    // alert(p.name);
    
    
    
    
    
    //protected：保护类型    在类里面、子类里面可以访问 ，在类外部没法访问
    
    
                //   class Person{
    
                //         protected name:string;  /*公有属性*/
    
                //         constructor(name:string){
                //             this.name=name;
                //         }
    
                //         run():string{
    
                //             return `${this.name}在运动`
                //         }
                //     }
                    // var p=new Person('王五');
                    // alert(p.run())
    
    
                    // class Web extends Person{
                    //     constructor(name:string){
    
                    //         super(name);  
                    //     }                  
                    //     work(){
    
                    //         alert(`${this.name}在工作`)
                    //     }
                    // }
    
                    // var w=new Web('李四11');
    
                    // w.work();
    
                    // alert( w.run());
    
    
                    
            //类外外部没法访问保护类型的属性
    
    
                    // class Person{
    
                    //     protected name:string;  /*保护类型*/
    
                    //     constructor(name:string){
                    //         this.name=name;
                    //     }
    
                    //     run():string{
    
                    //         return `${this.name}在运动`
                    //     }
                    // }
    
                    // var  p=new Person('哈哈哈');
    
                    // alert(p.name);
    
    
    
    
    
    // private ：私有        在类里面可以访问，子类、类外部都没法访问
                
    
                    // class Person{
    
                    //     private name:string;  /*私有*/
    
                    //     constructor(name:string){
                    //         this.name=name;
                    //     }
    
                    //     run():string{
    
                    //         return `${this.name}在运动`
                    //     }
                    // }
    
    
                    // class Web extends Person{
    
                    //     constructor(name:string){
                    //         super(name)
                    //     }
    
                    //     work(){
    
                    //         console.log(`${this.name}在工作`)
                    //     }
                    // }
    
    
    
        class Person{
    
            private name:string;  /*私有*/
    
            constructor(name:string){
                this.name=name;
            }
    
            run():string{
    
                return `${this.name}在运动`
            }
        }
    
        var p=new Person('哈哈哈');
    
        alert(p.run());

    // 静态属性 静态方法  

/*

    function Person(){
        this.run1=function(){

        }
    }
    Person.name='哈哈哈';

    Person.run2=function(){  静态方法


    }
    var p=new Person();

    Person.run2(); 静态方法的调用
*/



/*


        function $(element){

            return new Base(element)
        }

        $.get=function(){
            
        }

        function Base(element){

            this.element=获取dom节点;


            this.css=function(arr,value){

                this.element.style.arr=value;
            }
        }



        $('#box').css('color','red')


        $.get('url',function(){

        })
*/






    // class Per{
    //     public name:string;
    //     public age:number=20;
    //     //静态属性

    //     static sex="男";
    //     constructor(name:string) {
    //             this.name=name;
    //     }
    //     run(){  /*实例方法*/

    //         alert(`${this.name}在运动`)
    //     }
    //     work(){

    //         alert(`${this.name}在工作`)
    //     }
    //     static print(){  /*静态方法  里面没法直接调用类里面的属性*/

    //         alert('print方法'+Per.sex);
    //     }
    // }

    // // var p=new Per('张三');

    // // p.run();

    // Per.print();

    // alert(Per.sex);






//多态:父类定义一个方法不去实现，让继承它的子类去实现  每一个子类有不同的表现 

//多态属于继承
        /*


                class Animal {

                    name:string;
                    constructor(name:string) {
                        this.name=name;
                    }
                    eat(){
                        console.log('吃的方法')
                    }
                }

                class Dog extends Animal{
                    constructor(name:string){
                        super(name)
                    }
                    eat(){
                
                        return this.name+'吃粮食'
                    }
                }


                class Cat extends Animal{

                    constructor(name:string){
                        super(name)
                    }

                    eat(){

                        return this.name+'吃老鼠'
                    }
                }

        */



//抽象类：它是提供其他类继承的基类，不能直接被实例化。


//用abstract关键字定义抽象类和抽象方法，抽象类中的抽象方法不包含具体实现并且必须在派生类中实现。


// abstract抽象方法只能放在抽象类里面


// 抽象类和抽象方法用来定义标准 。   标准：Animal 这个类要求它的子类必须包含eat方法


abstract class Animal{
    
    public name:string;
    constructor(name:string){

        this.name=name;

    }
    abstract eat():any;  //抽象方法不包含具体实现并且必须在派生类中实现。
    
    run(){

        console.log('其他方法可以不实现')
    }
}


// var a=new Animal() /*错误的写法*/
 


class Dog extends Animal{

    //抽象类的子类必须实现抽象类里面的抽象方法
    constructor(name:any){
        super(name)
    }
    eat(){

        console.log(this.name+'吃粮食')
    }
}

var d=new Dog('小花花');
d.eat();




class Cat extends Animal{

    //抽象类的子类必须实现抽象类里面的抽象方法
    constructor(name:any){
        super(name)
    }
    run(){


    }
    eat(){

        console.log(this.name+'吃老鼠')
    }
    
}

var c=new Cat('小花猫');
c.eat();

/*
5、typeScript中的接口

    5.1 属性类接口
    5.2 函数类型接口
    5.3 可索引接口
    5.4 类类型接口
    5.5 接口扩展

   
*/


/*
接口的作用：在面向对象的编程中，接口是一种规范的定义，它定义了行为和动作的规范，在程序设计里面，接口起到一种限制和规范的作用。接口定义了某一批类所需要遵守的规范，接口不关心这些类的内部状态数据，也不关心这些类里方法的实现细节，它只规定这批类里必须提供某些方法，提供这些方法的类就可以满足实际需要。 typescrip中的接口类似于java，同时还增加了更灵活的接口类型，包括属性、函数、可索引和类等。

定义标准。

*/


// 1、属性接口     对json的约束



    //ts中定义方法
    /*
        function printLabel():void {
            console.log('printLabel');
        }
        printLabel();
    */


    //ts中定义方法传入参数
    /*

        function printLabel(label:string):void {
            console.log('printLabel');
        }

        printLabel('hahah');

    */



        /*
            ts中自定义方法传入参数,对json进行约束

        */

        /*
        
        function printLabel(labelInfo:{label:string}):void {
            console.log('printLabel');
        }

        printLabel('hahah'); //错误写法


        printLabel({name:'张三'});  //错误的写法


        printLabel({label:'张三'});  //正确的写法
    */



//对批量方法传入参数进行约束。


//接口：行为和动作的规范，对批量方法进行约束



        //就是传入对象的约束    属性接口
        //  interface FullName{

        //     firstName:string;   //注意;结束
        //     secondName:string;

        // }

        // function printName(name:FullName){

        //     // 必须传入对象  firstName  secondName
        //     console.log(name.firstName+'--'+name.secondName);
        // }
        // // printName('1213');  //错误

        // var obj={   /*传入的参数必须包含 firstName  secondName*/
        //     age:20,
        //     firstName:'张',
        //     secondName:'三'
        // };
        // printName(obj)







//  接口：行为和动作的规范，对批量方法进行约束

       

            // interface FullName{
            //     firstName:string;   //注意;结束
            //     secondName:string;
            // }

            // function printName(name:FullName){
            //     // 必须传入对象  firstName  secondName
            //     console.log(name.firstName+'--'+name.secondName);
            // }



            // function printInfo(info:FullName){

            //     // 必须传入对象  firstName  secondName
            //     console.log(info.firstName+info.secondName);
            // }

            // var obj={   /*传入的参数必须包含 firstName  secondName*/
            //     age:20,
            //     firstName:'张',
            //     secondName:'三'
            // };
            // printName(obj);


            // printInfo({
            //     firstName:'李',
            //     secondName:'四'
            // })





//接口 ：可选属性




    // interface FullName{

    //     firstName:string;
    //     secondName:string;
    // }

    // function getName(name:FullName){

    //     console.log(name)
    // }
    // //参数的顺序可以不一样
    // getName({        
    //     secondName:'secondName',
    //     firstName:'firstName'
    // })





    

    // interface FullName{
    //     firstName:string;
    //     secondName?:string;
    // }

    // function getName(name:FullName){

    //     console.log(name)
    // }  
    // getName({               
    //     firstName:'firstName'
    // })







/*
       $.ajax({
             type: "GET",
             url: "test.json",
             data: {username:$("#username").val(), content:$("#content").val()},
             dataType: "json"             
         });
         
*/


interface Config{
    type:string;
    url:string;
    data?:string;
    dataType:string;
}

//原生js封装的ajax 
function ajax(config:Config){

   var xhr=new XMLHttpRequest();

   xhr.open(config.type,config.url,true);

   xhr.send(config.data);

   xhr.onreadystatechange=function(){

        if(xhr.readyState==4 && xhr.status==200){
            console.log('chengong');


            if(config.dataType=='json'){

                console.log(JSON.parse(xhr.responseText));
            }else{
                console.log(xhr.responseText)

            }


        }
   }
}


ajax({
    type:'get',
    data:'name=zhangsan',
    url:'http://a.itying.com/api/productlist', //api
    dataType:'json'
})

/*
6、typeScript中的泛型

    6.1 泛型的定义
    6.2 泛型函数
    6.3 泛型类
    6.4 泛型接口
   
*/


/*

泛型：软件工程中，我们不仅要创建一致的定义良好的API，同时也要考虑可重用性。 组件不仅能够支持当前的数据类型，同时也能支持未来的数据类型，这在创建大型系统时为你提供了十分灵活的功能。

在像C#和Java这样的语言中，可以使用泛型来创建可重用的组件，一个组件可以支持多种类型的数据。 这样用户就可以以自己的数据类型来使用组件。


通俗理解：泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验)

*/


//只能返回string类型的数据

    // function getData(value:string):string{
    //     return value;
    // }

//同时返回 string类型 和number类型  （代码冗余）


    // function getData1(value:string):string{
    //     return value;
    // }


    // function getData2(value:number):number{
    //     return value;
    // }




//同时返回 string类型 和number类型       可以使用any


    //  function getData(value:any):any{
    //     return '哈哈哈';
    // }


    // getData(123);

    // getData('str');


    

//any放弃了类型检查,传入什么 返回什么。比如:传入number 类型必须返回number类型  传入 string类型必须返回string类型


    //传入的参数类型和返回的参数类型可以不一致
    //    function getData(value:any):any{
    //         return '哈哈哈';
    //     }




// 泛型：可以支持不特定的数据类型   要求：传入的参数和返回的参数一直



// T表示泛型，具体什么类型是调用这个方法的时候决定的

    //    function getData<T>(value:T):T{
    //        return value;
    //    }
    //     getData<number>(123);

        // getData<string>('1214231');


       // getData<number>('2112');       /*错误的写法*/  





    //    function getData<T>(value:T):any{
    //        return '2145214214';
    //    }

    //    getData<number>(123);  //参数必须是number

    //    getData<string>('这是一个泛型');








// 泛型类：比如有个最小堆算法，需要同时支持返回数字和字符串 a  -  z两种类型。  通过类的泛型来实现


    /*

            class MinClass{
                public list:number[]=[];
                add(num:number){
                    this.list.push(num)
                }
                min():number{
                    var minNum=this.list[0];
                    for(var i=0;i<this.list.length;i++){
                        if(minNum>this.list[i]){
                            minNum=this.list[i];
                        }
                    }
                    return minNum;
                }

            }

            var m=new MinClass();

            m.add(3);
            m.add(22);
            m.add(23);
            m.add(6);

            m.add(7);
            alert(m.min());

    */




//类的泛型

class MinClas<T>{

    public list:T[]=[];

    add(value:T):void{

        this.list.push(value);
    }

    min():T{        
        var minNum=this.list[0];
        for(var i=0;i<this.list.length;i++){
            if(minNum>this.list[i]){
                minNum=this.list[i];
            }
        }
        return minNum;
    }
}

var m1=new MinClas<number>();   /*实例化类 并且制定了类的T代表的类型是number*/
m1.add(11);
m1.add(3);
m1.add(2);
alert(m1.min())


var m2=new MinClas<string>();   /*实例化类 并且制定了类的T代表的类型是string*/

m2.add('c');
m2.add('a');
m2.add('v');
alert(m2.min())

//函数类型接口

    /*
        interface ConfigFn{

            (value1:string,value2:string):string;
        }


        var setData:ConfigFn=function(value1:string,value2:string):string{


            return value1+value2;
        }


        setData('name','张三');
    */




//1、泛型接口

        // interface ConfigFn{

        //     <T>(value:T):T;
        // }


        // var getData:ConfigFn=function<T>(value:T):T{

        //     return value;
        // }


        // // getData<string>('张三');


        // // getData<string>(1243);  //错误


//2、泛型接口



// interface ConfigFn<T>{
//     (value:T):T;
// }


// function getData<T>(value:T):T{

//     return value;
// }


// var myGetData:ConfigFn<string>=getData;     


// myGetData('20');  /*正确*/


// myGetData(20)  //错误
